/*
Copyright (C) 2011 The University of Michigan

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program.  If not, see <http://www.gnu.org/licenses/>.

Please send inquiries to powertutor@umich.edu
 */

package vn.cybersoft.obs.andriod.batterystats2.util;

import android.util.SparseArray;

import java.util.LinkedList;
import java.util.ListIterator;

public class HistoryBuffer {
	private static class UidData {
		public LinkedList<HistoryDatum> queue;
		public Counter sum;
		public Counter count;

		public UidData() {
			queue = new LinkedList<HistoryDatum>();
			sum = new Counter();
			count = new Counter();
		}
	}

	private static class HistoryDatum {
		public HistoryDatum() {
		}

		public void init(long iteration, int power) {
			this.iteration = iteration;
			this.power = power;
		}

		public long iteration;
		public int power;
	}

	private int maxSize;
	private SparseArray<UidData> uidData;

	public HistoryBuffer(int maxSize) {
		this.maxSize = maxSize;
		uidData = new SparseArray<UidData>();
	}

	/* The iteration should only increase across successive adds. */
	public synchronized void add(int uid, long iteration, int power) {
		UidData data = uidData.get(uid);
		if (data == null) {
			data = new UidData();
			uidData.put(uid, data);
		}
		data.count.add(1);
		if (power == 0) {
			return;
		}
		data.sum.add(power);
		if (maxSize == 0) {
			return;
		}

		LinkedList<HistoryDatum> queue = data.queue;
		HistoryDatum datum;
		if (maxSize <= queue.size()) {
			datum = queue.getLast();
			queue.removeLast();
		} else {
			datum = new HistoryDatum();
		}
		datum.init(iteration, power);
		queue.addFirst(datum);
	}

	/*
	 * Fills in the previous number timestamps starting from a timestamp and
	 * working backwards. Any timestamp with no information is just treated as
	 * using no power.
	 */
	public synchronized int[] get(int uid, long timestamp, int number) {
		int ind = 0;
		if (number < 0)
			number = 0;
		if (number > maxSize)
			number = maxSize;
		int[] ret = new int[number];
		UidData data = uidData.get(uid);
		LinkedList<HistoryDatum> queue = data == null ? null : data.queue;
		if (queue == null || queue.isEmpty()) {
			return ret;
		}
		if (timestamp == -1) {
			timestamp = queue.getFirst().iteration;
		}
		for (ListIterator<HistoryDatum> iter = queue.listIterator(); iter
				.hasNext();) {
			HistoryDatum datum = iter.next();
			while (datum.iteration < timestamp && ind < number) {
				ind++;
				timestamp--;
			}
			if (ind == number) {
				break;
			}
			if (datum.iteration == timestamp) {
				ret[ind++] = datum.power;
				timestamp--;
			} else {
				/* datum happened after requested interval. */
			}
		}
		return ret;
	}

	public synchronized long getTotal(int uid, int windowType) {
		UidData data = uidData.get(uid);
		return data == null ? 0 : data.sum.get(windowType);
	}

	public synchronized long getCount(int uid, int windowType) {
		UidData data = uidData.get(uid);
		return data == null ? 0 : data.count.get(windowType);
	}
}
